package com.tinyseed.emcp.api.productionRule.service.impl;

import com.google.common.collect.Lists;
import com.tinyseed.emcp.api.app.common.Constant;
import com.tinyseed.emcp.api.app.common.DateUtil;
import com.tinyseed.emcp.api.app.common.DicConstant;
import com.tinyseed.emcp.api.app.common.ListUtil;
import com.tinyseed.emcp.api.basicdata.repository.EnterpriseRepository;
import com.tinyseed.emcp.api.basicdata.repository.MonitorRepository;
import com.tinyseed.emcp.api.basicdata.repository.OrganizeRepository;
import com.tinyseed.emcp.api.basicdata.repository.WorkshopRepository;
import com.tinyseed.emcp.api.productionRule.bean.DeviceNodeOutputDTO;
import com.tinyseed.emcp.api.productionRule.bean.DistributionInputDTO;
import com.tinyseed.emcp.api.productionRule.bean.DistributionOutputDTO;
import com.tinyseed.emcp.api.productionRule.bean.ReductionOutputDTO;
import com.tinyseed.emcp.api.productionRule.entity.Distribution;
import com.tinyseed.emcp.api.productionRule.repository.DistributionRepository;
import com.tinyseed.emcp.api.productionRule.service.DistributionService;
import com.tinyseed.emcp.api.productionRule.service.ReductionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;

import java.text.NumberFormat;
import java.util.*;

@Service
@Slf4j
public class DistributionServiceImpl implements DistributionService {
    @Autowired
    private OrganizeRepository organizeRepository;
    @Autowired
    private EnterpriseRepository enterpriseRepository;
    @Autowired
    private WorkshopRepository workshopRepository;
    @Autowired
    private MonitorRepository monitorRepository;
    @Autowired
    private ReductionService reductionService;
    @Autowired
    private DistributionRepository distributionRepository;

    @Override
    @Cacheable
    public List<DeviceNodeOutputDTO> findOrganizeTree() {
        // 读取层次数据结果集列表
        List dataList = new ArrayList();
        /**
         * 机构信息
         */
        List<Map<String, Object>> organizes = organizeRepository.findOrganizes();
        if (!CollectionUtils.isEmpty(organizes)) {
            organizes.forEach(organize -> {
                HashMap dataRecord = new HashMap();
                dataRecord.put("id", organize.get("id"));
                dataRecord.put("name", organize.get("organize_name"));
                dataRecord.put("pid", organize.get("parent_id"));
                dataRecord.put("type", Constant.TREE_NODE_ORGANIZE);
                dataList.add(dataRecord);
            });
        }

        /**
         * 企业信息
         */
        List<Map<String, Object>> enterprises = enterpriseRepository.findEnterprises();
        if (!CollectionUtils.isEmpty(enterprises)) {
            enterprises.forEach(enterprise -> {
                HashMap dataRecord = new HashMap();
                dataRecord.put("id", Constant.ENTERPRISE_ID_REFIX + enterprise.get("id"));
                dataRecord.put("name", enterprise.get("enterprise_name"));
                dataRecord.put("pid", enterprise.get("organize_id"));
                dataRecord.put("type", Constant.TREE_NODE_ENTERPRISE);
                dataList.add(dataRecord);
            });
        }

        /**
         * 车间信息
         */
        List<Map<String, Object>> workshops = workshopRepository.findWorks();
        if (!CollectionUtils.isEmpty(workshops)) {
            workshops.forEach(workshop -> {
                HashMap dataRecord = new HashMap();
                dataRecord.put("id", Constant.WORKSHOP_ID_REFIX + workshop.get("id"));
                dataRecord.put("name", workshop.get("shop_name"));
                dataRecord.put("pid", Constant.ENTERPRISE_ID_REFIX + workshop.get("enterprise_id"));
                dataRecord.put("type", Constant.TREE_NODE_WORKSHOP);
                dataList.add(dataRecord);
            });
        }

        /**
         * 监控器
         */
        List<Map<String, Object>> monitors = monitorRepository.findMonitors();
        if (!CollectionUtils.isEmpty(monitors)) {
            monitors.forEach(monitor -> {
                HashMap dataRecord = new HashMap();
                HashMap mpp = new HashMap();
                HashMap mrp = new HashMap();
                if (monitor.get("equipment_type").equals(Constant.MONITOR_PRODUCE_POLLUTION)) {
                    //产污监控点
                    mpp.put("id", Constant.MONITOR_PRODUCE_POLLUTION_ID_REFIX + monitor.get("shop_id"));
                    mpp.put("name", "产污监控点");
                    mpp.put("pid", Constant.WORKSHOP_ID_REFIX + monitor.get("shop_id"));
                    mpp.put("type", Constant.TREE_NODE_MONITOR);
                    dataList.add(mpp);
                    //产污
                    dataRecord.put("id", Constant.MONITOR_ID_REFIX + monitor.get("id"));
                    dataRecord.put("name", monitor.get("monitor_name"));
                    dataRecord.put("pid", Constant.MONITOR_PRODUCE_POLLUTION_ID_REFIX + monitor.get("shop_id"));
                    dataRecord.put("type", Constant.TREE_NODE_MONITOR);
                } else {
                    //治污监控点
                    mrp.put("id", Constant.MONITOR_REDUCE_POLLUTION_ID_REFIX + monitor.get("shop_id"));
                    mrp.put("name", "治污监控点");
                    mrp.put("pid", Constant.WORKSHOP_ID_REFIX + monitor.get("shop_id"));
                    mrp.put("type", Constant.TREE_NODE_MONITOR);
                    dataList.add(mrp);
                    //治污
                    dataRecord.put("id", Constant.MONITOR_ID_REFIX + monitor.get("id"));
                    dataRecord.put("name", monitor.get("monitor_name"));
                    dataRecord.put("pid", Constant.MONITOR_REDUCE_POLLUTION_ID_REFIX + monitor.get("shop_id"));
                    dataRecord.put("type", Constant.TREE_NODE_MONITOR);
                }
                dataList.add(dataRecord);
            });
        }

        // 节点列表（散列表，用于临时存储节点对象）
        HashMap nodeList = new HashMap();
        // 根节点集合
        List<DeviceNodeOutputDTO> nodes = Lists.newArrayList();

        // 根据结果集构造节点列表（存入散列表）
        for (Iterator it = dataList.iterator(); it.hasNext(); ) {
            Map dataRecord = (Map) it.next();
            DeviceNodeOutputDTO node = new DeviceNodeOutputDTO();
            node.setId(dataRecord.get("id").toString());
            node.setName(dataRecord.get("name").toString());
            if (dataRecord.get("pid") == null || dataRecord.get("pid").equals("") || dataRecord.get("pid").equals("null")) {
                node.setPid(null);
            } else {
                node.setPid(dataRecord.get("pid").toString());
            }
            node.setType(dataRecord.get("type").toString());
            nodeList.put(node.getId(), node);
        }
        // 构造无序的多叉树
        Set entrySet = nodeList.entrySet();
        for (Iterator it = entrySet.iterator(); it.hasNext(); ) {
            DeviceNodeOutputDTO node = (DeviceNodeOutputDTO) ((Map.Entry) it.next()).getValue();
            if (node.getPid() == null || node.getPid().equals("") || node.getPid().equals("0") || node.getPid().equals("null")) {
                nodes.add(node);
            } else {
                ((DeviceNodeOutputDTO) nodeList.get(node.getPid())).addChild(node);
            }
        }

        return nodes;
    }

    @Override
    public List<Map<String, String>> queryReductionList() {
        List<ReductionOutputDTO> dtos = reductionService.getList();
        List<Map<String, String>> list = new ArrayList<>();
        for (ReductionOutputDTO dto : dtos) {
            Map<String, String> map = new HashMap<>();
            String reductionInfo = DicConstant.formatterLevel(dto.getLevel()) + " " + DicConstant.formatterProduceType(dto.getProduceType()) + " " + formatterDouble(dto.getLessProduce()) + " " +
                    DateUtil.formatDateTime(dto.getStartTime()) + " ~ " + DateUtil.formatDateTime(dto.getEndTime()) + " " + DicConstant.formatterEnable(dto.getActive());
            map.put("id", dto.getId().toString());
            map.put("name", reductionInfo);
            list.add(map);
        }
        return list;
    }

    /**
     * Double 转 百分比
     *
     * @param d
     * @return
     */
    public String formatterDouble(Double d) {
        if (d == null) {
            return "";
        }
        NumberFormat num = NumberFormat.getPercentInstance();
        return num.format(d / 100);
    }

    @Override
    public List<DistributionOutputDTO> findAllByProducesetId(Long id) {
        if (StringUtils.isEmpty(id)) {
            return new ArrayList<>();
        }
        List<Distribution> list = distributionRepository.findAllByProducesetId(id);
        return ListUtil.copy(list, DistributionOutputDTO.class);
    }

    @Transactional
    @Override
    public void saveDistributions(DistributionInputDTO distributionInputDTO) {
        List<Distribution> distributions = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        String monitorIds = distributionInputDTO.getMonitorIds().replace(Constant.MONITOR_ID_REFIX, "");
        String[] monitorIdList = monitorIds.split(",");
        Long[] adArray = new Long[monitorIdList.length];
        for (int i = 0; i < monitorIdList.length; i++) {
            adArray[i] = Long.valueOf(monitorIdList[i]);
        }
        //删除已存在被绑定的监控点
        distributionRepository.deleteAllByMonitorIdIsIn(adArray);
        //遍历监控点
        for (int i = 0; i < monitorIdList.length; i++) {
            Distribution distribution = new Distribution();
            distribution.setProducesetId(Long.valueOf(distributionInputDTO.getProducesetId()));
            distribution.setMonitorId(Long.valueOf(monitorIdList[i]));
            distributions.add(distribution);
        }
        //删除原有关系
        distributionRepository.deleteAllByProducesetId(distributionInputDTO.getProducesetId());
        //批量插入新关系
        distributionRepository.saveAll(distributions);
    }
    @Override
    @Transactional
    public void saveRules(List<DistributionInputDTO> distributionInputDTOList) {

        Long producesetId = distributionInputDTOList.get(0).getProducesetId();

        if (producesetId != null) {
            // 批量删除原有关系
            distributionRepository.deleteAllByProducesetId(producesetId);
        }

        if (CollectionUtils.isEmpty(distributionInputDTOList)) {
            return;
        }
        // 获取需要存储的数据
        List<Distribution> distributions = ListUtil.copy(distributionInputDTOList, Distribution.class);
        // 存储数据
        distributionRepository.saveAll(distributions);

    }

    @Transactional
    @Override
    public void deleteAllByProducesetIdIsIn(List<Long> producesetIds) {
        distributionRepository.deleteAllByProducesetIdIsIn(producesetIds);
    }

    /*获取规则关系表*/
    @Override
    @Transactional
    public Page<DistributionOutputDTO> getDistributionRules(int current, int size) {
        StopWatch stopWatch = new StopWatch("计算查找耗时");
        stopWatch.start("任务一");
        Pageable pageable = PageRequest.of(current, size);
        Page<Distribution> distributionPage = distributionRepository.findAll(pageable);
        List<DistributionOutputDTO> toList = new ArrayList<>();
        /*因为是懒加载，所以company需要取出来后重新赋值*/
        distributionPage.getContent().forEach(item -> {
            DistributionOutputDTO distributionOutputDTO = new DistributionOutputDTO();
            BeanUtils.copyProperties(item, distributionOutputDTO);
            /*提取关键信息返回给前端，按需加载一些外部字段*/
//            distributionOutputDTO.setMonitorName(item.getMonitor().getMonitorName());

//            distributionOutputDTO.setEnterpriseName(item.getEnterprise().getEnterpriseName());
//            distributionOutputDTO.setWorkshopName(item.getWorkshop().getShopName());
            toList.add(distributionOutputDTO);
        });

        stopWatch.stop();
        log.info(stopWatch.prettyPrint());

        return ListUtil.buildPage(distributionPage, toList);
    }
}
